package com.haoran.handler;

import java.util.Date;
import java.util.logging.Level;

import com.haoran.config.NettyConfig;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.CharsetUtil;

/**
 * 可定制的web-socket处理程序
 *
 */
public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
	private static final java.util.logging.Logger logger = java.util.logging.Logger
			.getLogger(WebSocketServerHandler.class.getName());

	private WebSocketServerHandshaker handshaker;

	/**
	 * 客户端与服务端创建连接的时候调用
	 * 
	 * @param ctx
	 * @throws Exception
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		NettyConfig.CHANNEL_GROUP.add(ctx.channel());
		System.out.println("客户端与服务端连接开启");
	}

	/**
	 * 客户端与服务端断开连接的时候调用
	 * 
	 * @param ctx
	 * @throws Exception
	 */
	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		NettyConfig.CHANNEL_GROUP.remove(ctx.channel());
		System.out.println("客户端与服务端连接关闭");
	}

	/**
	 * 服务端接收客户端发送过来的数据结束之后调用
	 */
	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.flush();
	}

	/**
	 * 工程出现异常的时候调用
	 */
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		cause.printStackTrace();
		ctx.close();
	}

	/**
	 * 服务端处理客户端websocket请求的核心方法
	 */
	@Override
	protected void messageReceived(ChannelHandlerContext ctx, Object req) throws Exception {
		// 传统的http接入
		if (req != null && req instanceof FullHttpRequest) {
			handleHttpRequest(ctx, (FullHttpRequest) req);
		}
		// webSocket 接入
		if (req != null && req instanceof WebSocketFrame) {
			handleWebSocketFrame(ctx, (WebSocketFrame) req);
		}
	}

	private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
		// 判断是否是关闭链接的指令
		if (frame instanceof CloseWebSocketFrame) {
			handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
			return;
		}
		// 判断是否是Ping消息
		if (frame instanceof PingWebSocketFrame) {
			ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
		}
		// 本例只支持文本信息不支持二进制信息
		if (!(frame instanceof TextWebSocketFrame)) {
			throw new UnsupportedOperationException(
					String.format("%s frame types not supported ", frame.getClass().getName()));
		}
		// 返回应答消息
		String request = ((TextWebSocketFrame) frame).text();
		if (logger.isLoggable(Level.FINE)) {
			logger.fine(String.format("%s received %s", ctx.channel(), request));
		}
		TextWebSocketFrame msg = new TextWebSocketFrame("欢迎使用Netty WebSocket服务，现在时刻：" + new Date().toString());
		ctx.channel().write(msg);
		//群发
		TextWebSocketFrame gmsg = new TextWebSocketFrame("现在时刻：" + new Date().toString()+ctx.channel().id() + "===>>>" + request);
		NettyConfig.CHANNEL_GROUP.writeAndFlush(gmsg);
	}

	private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
		if (!req.decoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) {
			sendHttpResponse(ctx, req,
					new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
			return;
		}
		// 构造握手 响应返回
		WebSocketServerHandshakerFactory handshakerFactory = new WebSocketServerHandshakerFactory(
				"ws://localhost:8080/websocket", null, false);
		handshaker = handshakerFactory.newHandshaker(req);
		if (handshaker == null) {
			WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
		} else {
			handshaker.handshake(ctx.channel(), req);
		}
	}

	private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req,
			DefaultFullHttpResponse res) {
		// 返回应答给客户端
		if (res.status().code() != 200) {
			ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);
			res.content().writeBytes(buf);
			buf.release();
			setContentLength(res, res.content().readableBytes());

		}
		ChannelFuture f = ctx.channel().writeAndFlush(res);
		if (!isKeepAlive(req) || res.status().code() != 200) {
			f.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
		}
	}

	private boolean isKeepAlive(FullHttpRequest req) {
		return false;
	}

	private void setContentLength(DefaultFullHttpResponse res, int readableBytes) {
		
	}
}
